<?php

declare(strict_types=1);

namespace app\controller\system;

use app\BaseController;
use app\model\SysMenu;
use app\service\factory\ResponseFactory;
use app\service\sys\MenuService;
use app\validate\system\SysMenuValidate;
use InvalidArgumentException;
use think\Response;
use Throwable;

class Menu extends BaseController
{
    public function index(MenuService $menuService): Response
    {
        try {
            $filters = $this->request->only([
                'client_type',
                'status',
                'is_visible',
                'type',
                'keyword',
                'include_buttons',
                'include_disabled',
            ], 'get');

            $filters = array_filter(
                $filters,
                static fn($value) => $value !== null && $value !== ''
            );

            $collection = $menuService->getMenuCollection($filters);
            $tree = $menuService->buildTree($collection);
            $total = count($collection);

            return json(ResponseFactory::paginated(
                $tree,
                $total,
                1,
                $total > 0 ? $total : 1
            ));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function save(MenuService $menuService): Response
    {
        try {
            $payload = $this->request->only([
                'parent_id',
                'type',
                'name',
                'identifier',
                'path',
                'component',
                'redirect',
                'meta',
                'permission_code',
                'client_type',
                'sort',
                'is_visible',
                'status',
            ], 'post');

            $this->validate($payload, SysMenuValidate::class . '.create');

            $menu = $menuService->create($payload);

            return json(ResponseFactory::success($menuService->formatMenu($menu), '菜单已创建'));
        } catch (InvalidArgumentException $e) {
            return json(ResponseFactory::error($e->getMessage(), 422));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function update(int $id, MenuService $menuService): Response
    {
        try {
            /** @var SysMenu|null $menu */
            $menu = SysMenu::find($id);
            if (!$menu) {
                return json(ResponseFactory::error('菜单不存在', 404));
            }

            $payload = $this->request->only([
                'parent_id',
                'type',
                'name',
                'identifier',
                'path',
                'component',
                'redirect',
                'meta',
                'permission_code',
                'client_type',
                'sort',
                'is_visible',
                'status',
            ], 'put');

            if ($payload === []) {
                return json(ResponseFactory::error('没有任何可更新的字段', 422));
            }

            $payload['id'] = $id;
            $this->validate($payload, SysMenuValidate::class . '.update');

            $updated = $menuService->update($menu, $payload);

            return json(ResponseFactory::success($menuService->formatMenu($updated), '菜单已更新'));
        } catch (InvalidArgumentException $e) {
            return json(ResponseFactory::error($e->getMessage(), 422));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function delete(int $id, MenuService $menuService): Response
    {
        try {
            /** @var SysMenu|null $menu */
            $menu = SysMenu::find($id);
            if (!$menu) {
                return json(ResponseFactory::error('菜单不存在', 404));
            }

            $menuService->delete($menu);

            return json(ResponseFactory::success(true, '菜单已删除'));
        } catch (InvalidArgumentException $e) {
            return json(ResponseFactory::error($e->getMessage(), 422));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }
}
